package org.ngame.socket.protocol;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.ngame.socket.exeptions.LimitExedeedException;
import java.nio.ByteOrder;

/**
 * 字节流协议的实现
 *
 * @author beykery
 */
public class LVProtocol extends Protocol
{

  private static final InternalLogger LOG =InternalLoggerFactory.getInstance(LVProtocol.class);
  private ByteBuf incompleteframe;//尚未完成的帧
  private byte h, l;//高低字节用来记录长度
  private byte status;//当前状态
  private static final byte STATUS_H = 0;
  private static final byte STATUS_L = 1;
  private static final byte STATUS_C = 2;

  /**
   * 构造
   */
  public LVProtocol()
  {
  }

  @Override
  public ByteBuf translateFrame(ByteBuf readBuffer) throws Exception
  {
    while (readBuffer.isReadable())
    {
      switch (status)
      {
        case STATUS_H:
          h = readBuffer.readByte();
          status = STATUS_L;
          break;
        case STATUS_L:
          l = readBuffer.readByte();
          final int blen = Protocol.order == ByteOrder.BIG_ENDIAN ? (0x0000ff00 & (h << 8)) | (0x000000ff & l) : (0x0000ff00 & (l << 8)) | (0x000000ff & h);
          if (context != null)
          {
            if (blen <= 0 || blen > maxFrameSize)
            {
              throw new LimitExedeedException("帧长度非法:" + h + "/" + l + ":" + blen);
            }
          }
          incompleteframe = PooledByteBufAllocator.DEFAULT.buffer(blen + 16 + 2);
          incompleteframe = incompleteframe.order(Protocol.order);
          incompleteframe.writeShort(blen);
          status = STATUS_C;
          break;
        case STATUS_C:
          int len = incompleteframe.writableBytes() - 16;
          len = len < readBuffer.readableBytes() ? len : readBuffer.readableBytes();
          //incompleteframe.writeBytes(readBuffer, len);
          if (readBuffer.hasMemoryAddress())
          {
            PlatformDependent.copyMemory(readBuffer.memoryAddress() + readBuffer.readerIndex(), incompleteframe.memoryAddress() + incompleteframe.writerIndex(), len);
          } else if (readBuffer.hasArray())
          {
            PlatformDependent.copyMemory(readBuffer.array(), readBuffer.arrayOffset() + readBuffer.readerIndex(), incompleteframe.memoryAddress() + incompleteframe.writerIndex(), len);
          }
          incompleteframe.writerIndex(incompleteframe.writerIndex() + len);
          readBuffer.readerIndex(readBuffer.readerIndex() + len);
          if ((incompleteframe.writableBytes() - 16) <= 0)
          {
            status = STATUS_H;
            return incompleteframe;
          }
          break;
      }
    }
    return null;
  }

  @Override
  public int headerLen()
  {
    return 2;
  }

  @Override
  public void release()
  {
    if (incompleteframe != null && incompleteframe.refCnt() > 0)
    {
      ReferenceCountUtil.release(this.incompleteframe, incompleteframe.refCnt());
    }
  }
}
